#include "tcp_server.h"
#include "acceptor.h"
#include "event_loop.h"
#include "event_loop_thread_pool.h"
#include "inet_address.h"
#include "logger.h"

#include <functional>
#include <strings.h>

#include "tcp_connection.h"

static EventLoop *check_loop_not_null(EventLoop *loop) {
    if (loop == nullptr) {
        LOG_FATAL("%s:%s:%d main_loop is null! \n", __FILE__, __func__,__LINE__);
    }
    return loop;
}

TcpServer::TcpServer(EventLoop *loop, const InetAddress &listen_addr, const std::string &name_arg,
                   Option option)
    : loop_(check_loop_not_null(loop)), ip_port_(listen_addr.to_ip_port()), name_(name_arg),
      acceptor_(new Acceptor(loop, listen_addr, option == kReusePort)),
      thread_pool_(new EventLoopThreadPool(loop, name_)), connection_callback_(),
      message_callback_(), next_conn_id_(1),started_(0){
    // 当有先用户连接时，会执行tcp_server::new_connection回调
    acceptor_->set_new_connection_callback(
        std::bind(&TcpServer::new_connection, this, std::placeholders::_1, std::placeholders::_2));
}

TcpServer::~TcpServer() {
    for (auto &item:connections_) {
        //这个局部的shared_ptr智能指针对象，出右括号，可以自动释放new出来的TcpConnection对象资源了
        TcpConnectionPtr conn(item.second);

        //销毁连接
        conn->get_loop()->run_in_loop(
            std::bind(&TcpConnection::connect_destroyed,conn));
    }

}


// 先设置底层subloop的个数
void TcpServer::set_thread_num(int num_threads) { thread_pool_->set_thread_num(num_threads); }

// 开启服务器监听 loop.loop()
void TcpServer::start() {
    if (started_++ == 0) // 防止一个tcp_server对象被start多次
    {
        thread_pool_->start(thread_init_callback_); // 启动底层loop线程池
        loop_->run_in_loop(std::bind(&Acceptor::listen, acceptor_.get()));
    }
}

//有一个新的客户端的链接，acceptor会执行这个回调操作
void TcpServer::new_connection(int sockfd, const InetAddress &peer_addr) {
    //轮询算法，选择一个subloop,来管理channel
    EventLoop *io_loop = thread_pool_->get_next_loop();
    char buf[64]={0};
    snprintf(buf,sizeof buf, "-%s#%d",ip_port_.c_str(),next_conn_id_);
    ++next_conn_id_;
    std::string conn_name= name_+buf;
    LOG_INFO("TcpServer::new_connection [%s] - new connection [%s] from %s \n",name_.c_str(),conn_name.c_str(),peer_addr.to_ip_port().c_str());

    //通过sockfd获取器绑定的本机的ip地址和端口信息
    sockaddr_in local{};
    ::bzero(&local,sizeof(local));
    socklen_t addrlen = sizeof local;
    if (::getsockname(sockfd,(sockaddr*)&local,&addrlen)<0) {
        LOG_ERROR("sockets::get_local_addr");
    }
    InetAddress local_addr(local);
    //根据成功连接的sockfd,创建TcpConnection连接对象
    TcpConnectionPtr conn(new TcpConnection(
                io_loop,
                conn_name,
                sockfd,//sockfd_channel
                local_addr,
                peer_addr));
    connections_[conn_name]= conn;
    //下面的回调都是用户设置给TcpServer=>TcpConnection=> Channel=> Poller=>notify channel 调用回调
    conn->set_connection_callback(connection_callback_);
    conn->set_message_callback(message_callback_);
    conn->set_write_complete_callback(write_complete_callback_);


    //设置了如何关闭连接的回调
    conn->set_close_callback(
        std::bind(&TcpServer::remove_connection,this,std::placeholders::_1));

    //直接调用TcpConnection::connect_established
    io_loop->run_in_loop(std::bind(&TcpConnection::connect_established,conn));
}

void TcpServer::remove_connection(const TcpConnectionPtr &conn) {
    loop_->run_in_loop(
        std::bind(&TcpServer::remove_connection_in_loop,this,conn));
}

void TcpServer::remove_connection_in_loop(const TcpConnectionPtr &conn) {
    LOG_INFO("TcpServer::remove_connection_in_loop [%s] - connection %s \n",name_.c_str(),conn->name().c_str());

    connections_.erase(conn->name());
    EventLoop *io_loop = conn->get_loop();
    io_loop->queue_in_loop(std::bind(&TcpConnection::connect_destroyed,conn));
}
